package com.kaibes.web.base;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;

import com.kaibes.web.filter.DoFilterInternal;
import com.kaibes.web.filter.FilterInternal;

@Order(1)
@Component
public class HttpMethodOverrideDoFilter implements DoFilterInternal {

    private static final List<String> ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.GET.name()));

    private String methodParam = HttpMethodOverrideConsts.DEFAULT_METHOD_PARAM;
    private String headerParam = HttpMethodOverrideConsts.DEFAULT_HEADER_PARAM;
    
    @Override
    public void doFilterInternal(FilterInternal filterInternal) throws ServletException, IOException {
        HttpServletRequest request = filterInternal.getRequest();
        String method = request.getMethod();
        
        if ("POST".equals(method) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
            String temp = request.getParameter(this.methodParam);
            if (StringUtils.hasLength(temp)) {
                temp = temp.toUpperCase(Locale.ENGLISH);
            } else {
                temp = request.getHeader(headerParam);
                if (StringUtils.hasLength(temp)) {
                    temp = temp.toUpperCase(Locale.ENGLISH);
                }
            }
            if (StringUtils.hasLength(temp) && ALLOWED_METHODS.contains(temp)) {
                method = temp;
            }
        }
        if (!method.equals(request.getMethod())) {
            request = new MethodOverrideWrapper(request, method);
            filterInternal.setRequest(request);
        }
        
    }

    private static class MethodOverrideWrapper extends HttpServletRequestWrapper {

        private String method = null;
        
        public MethodOverrideWrapper(HttpServletRequest request, String method) {
            super(request);
            this.method = method;
        }
        
        @Override
        public String getMethod() {
            return method;
        }
        
    }
}
